package com.gonsin.gnews;

import com.gonsin.gnews.annotations.*;
import com.gonsin.gnews.annotations.exceptions.GNewsException;
import com.gonsin.gnews.annotations.model.*;
import com.gonsin.gnews.annotations.services.SenderService;
import com.gonsin.gnews.mapper.NewsTemplateMapper;
import com.gonsin.gnews.service.NewsCache;
import com.gonsin.gnews.utils.FreemarkerUtils;
import com.gonsin.i18n.logic.T;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.BooleanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.io.Serializable;
import java.util.*;

import static com.gonsin.gnews.NewsUtils.toPageable;

/**
 * 消息处理逻辑
 */
@Primary
@Slf4j
@Service
public class NewsServiceImpl implements INewsService {

    @Autowired
    private NewsTemplateMapper newsTemplateMapper;
    @Autowired
    private NewsConfig newsConfig;
    @Autowired
    private SenderService senderService;
    @Autowired
    private NewsCache cache;
    @Autowired
    private NewsContextManager contextManager;

    private final Gson gson = new GsonBuilder().create();

    @Override
    public void sendNews(String edificeKey, Object message, Serializable... targets) {
        if (ArrayUtils.isEmpty(targets)) {
            return;
        }

        NewsStructPo structPo = newsConfig.getNewsStruct(message.getClass());
        if (structPo == null) {
            throw new GNewsException("【%s】不属于一个消息模板，请查看该类是否添加了@GNews批注", message.getClass());
        }

        List<NewsTemplateBean> beans = findTemplates(edificeKey, structPo.getKey(), null);
        if (CollectionUtils.isEmpty(beans)) {
            if (GNewsEnvironment.LOG) {
                log.warn("查找不到模板");
            }
            return;
        }

        for (NewsTemplateBean b : beans) {
            GNewsSenderDescriber sender = senderService.getSender(b.getPlatform());
            if (sender == null) {
                continue;
            }

            // 构建消息体
            GNewsBody newsBody = createNewsBody(sender, b, message);
            GNewsContext context = contextManager.getContext(edificeKey, sender.getPlatform());
            sender.getSender().sendNews(context, newsBody, Arrays.asList(targets));
        }
    }

    @Override
    public void sendNews(String edificeKey, String platform, Object message, Serializable... targets) {
        if (ArrayUtils.isEmpty(targets)) {
            return;
        }

        NewsStructPo structPo = newsConfig.getNewsStruct(message.getClass());
        if (structPo == null) {
            throw new GNewsException("【%s】不属于一个消息模板，请查看该类是否添加了@GNews批注", message.getClass());
        }

        List<NewsTemplateBean> beans = findTemplates(edificeKey, structPo.getKey(), platform);
        if (CollectionUtils.isEmpty(beans)) {
            if (GNewsEnvironment.LOG) {
                log.warn("查找不到模板");
            }
            return;
        }

        for (NewsTemplateBean b : beans) {
            GNewsSenderDescriber sender = senderService.getSender(b.getPlatform());
            if (sender == null) {
                continue;
            }

            // 构建消息体
            GNewsBody newsBody = createNewsBody(sender, b, message);
            GNewsContext context = contextManager.getContext(edificeKey, sender.getPlatform());
            sender.getSender().sendNews(context, newsBody, Arrays.asList(targets));
        }
    }

    /**
     * 构建消息内容
     *
     * @param sender   消息发送器的描述
     * @param template 消息模板
     * @param message  消息内容的变量
     * @return
     */
    private GNewsBody createNewsBody(GNewsSenderDescriber sender, NewsTemplateBean template, Object message) {
        GNewsBody body = new GNewsBody();

        if (null != template) {
            body.setTemplateKey(template.getTemplateKey());
            // 保存模板和参数内容，用于站内信翻译
            body.setTemplateContent(template.getContent());
            body.setTemplateParams(gson.toJson(message));
        }

        if (sender.isSupportContent()) {
            String content = FreemarkerUtils.generalString(template.getContent(), message);
            body.setContent(content);
        }

        if (sender.isSupportLink()) {
            String link = FreemarkerUtils.generalString(template.getUrl(), message);
            body.setLink(link);
        }

        if (sender.isSupportTitle()) {
            String title = FreemarkerUtils.generalString(template.getTitle(), message);
            body.setTitle(title);
        }

        if (sender.isSupportTemplateCode()) {
            body.setTemplateCode(template.getTemplateCode());
        }

        if (sender.isSupportRows()) {
            List<GNewsRow> paramValues = new ArrayList<>();
            template.getParams().forEach((v) -> {
                GNewsRow po = new GNewsRow();
                po.setLeft(FreemarkerUtils.generalString(v.getKey(), message));
                po.setRight(FreemarkerUtils.generalString(v.getValue(), message));
                paramValues.add(po);
            });
            body.setRows(paramValues);
        }

        return body;
    }

    private List<NewsTemplateBean> findTemplates(String edificeKey, String templateKey, String platform) {

        List<NewsTemplateBean> newsTemplate = cache.get(edificeKey + "-" + templateKey);
        if (newsTemplate != null && !newsTemplate.isEmpty()) {
            for(NewsTemplateBean newsTemplateBean : newsTemplate){
                if(BooleanUtils.isTrue(newsTemplateBean.getInit())){
                    newsTemplateBean.setContent(T.t(newsTemplateBean.getContent()));
                }
            }
            return newsTemplate;
        }
        NewsTemplateSearchPo searchPo = new NewsTemplateSearchPo();
        searchPo.setTemplateKey(templateKey);
        searchPo.setPlatform(platform);
        searchPo.setEnable(true);
        GNewsPageRequest pageRequest = new GNewsPageRequest();
        pageRequest.setPage(0);
        pageRequest.setCount(Integer.MAX_VALUE);
        List<NewsTemplateBean> list = newsTemplateMapper.searchTemplates(edificeKey, searchPo, toPageable(pageRequest));
        for(NewsTemplateBean newsTemplateBean : list){
            if(BooleanUtils.isTrue(newsTemplateBean.getInit())){
                newsTemplateBean.setContent(T.t(newsTemplateBean.getContent()));
            }
        }
        cache.put(edificeKey + "-" + templateKey, list);
        return list;
    }


}
